//==--- TypeProperties.td - Type property definitions ---------------------===//
//
// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
// See https://llvm.org/LICENSE.txt for license information.
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
//
//===----------------------------------------------------------------------===//

include "clang/AST/PropertiesBase.td"
include "clang/Basic/TypeNodes.td"

let Class = ComplexType in {
  def : Property<"elementType", QualType> {
    let Read = [{ node->getElementType() }];    
  }

  def : Creator<[{ return ctx.getComplexType(elementType); }]>;
}

let Class = PointerType in {
  def : Property<"pointeeType", QualType> {
    let Read = [{ node->getPointeeType() }];
  }

  def : Creator<[{ return ctx.getPointerType(pointeeType); }]>;
}

let Class = AdjustedType in {
  def : Property<"originalType", QualType> {
    let Read = [{ node->getOriginalType() }];
  }
  def : Property<"adjustedType", QualType> {
    let Read = [{ node->getAdjustedType() }];
  }

  def : Creator<[{ return ctx.getAdjustedType(originalType, adjustedType); }]>;
}

let Class = DecayedType in {
  def : Override {
    // We don't need to serialize the adjusted type because we can always
    // derive it by decaying the original type.
    let IgnoredProperties = [ "adjustedType" ];
  }

  def : Creator<[{ return ctx.getAdjustedParameterType(originalType); }]>;
}

let Class = BlockPointerType in {
  def : Property<"pointeeType", QualType> {
    let Read = [{ node->getPointeeType() }];
  }

  def : Creator<[{ return ctx.getBlockPointerType(pointeeType); }]>;
}

let Class = ReferenceType in {
  def : Property<"pointeeTypeAsWritten", QualType> {
    let Read = [{ node->getPointeeTypeAsWritten() }];
  }
}

let Class = LValueReferenceType in {
  def : Property<"isSpelledAsLValue", Bool> {
    let Read = [{ node->isSpelledAsLValue() }];
  }

  def : Creator<[{
    return ctx.getLValueReferenceType(pointeeTypeAsWritten,
                                      isSpelledAsLValue);
  }]>;
}

let Class = RValueReferenceType in {
  def : Creator<[{
    return ctx.getRValueReferenceType(pointeeTypeAsWritten);
  }]>;
}

let Class = MemberPointerType in {
  def : Property<"pointeeType", QualType> {
    let Read = [{ node->getPointeeType() }];
  }
  def : Property<"baseType", QualType> {
    let Read = [{ QualType(node->getClass(), 0) }];
  }

  def : Creator<[{
    return ctx.getMemberPointerType(pointeeType, baseType.getTypePtr());
  }]>;
}

let Class = ArrayType in {
  def : Property<"elementType", QualType> {
    let Read = [{ node->getElementType() }];
  }
  def : Property<"sizeModifier", ArraySizeModifier> {
    let Read = [{ node->getSizeModifier() }];
  }
  def : Property<"indexQualifiers", Qualifiers> {
    let Read = [{ Qualifiers::fromCVRMask(node->getIndexTypeCVRQualifiers()) }];
  }
}

let Class = ConstantArrayType in {
  def : Property<"sizeValue", APInt> {
    let Read = [{ node->getSize() }];
  }
  def : Property<"size", ExprRef> {
    let Read = [{ node->getSizeExpr() }];
  }

  def : Creator<[{
    return ctx.getConstantArrayType(elementType, sizeValue, size,
                                    sizeModifier,
                                    indexQualifiers.getCVRQualifiers());
  }]>;
}

let Class = IncompleteArrayType in {
  def : Creator<[{
    return ctx.getIncompleteArrayType(elementType, sizeModifier,
                                      indexQualifiers.getCVRQualifiers());
  }]>;
}

let Class = VariableArrayType in {
  def : Property<"leftBracketLoc", SourceLocation> {
    let Read = [{ node->getLBracketLoc() }];
  }
  def : Property<"rightBracketLoc", SourceLocation> {
    let Read = [{ node->getRBracketLoc() }];
  }
  def : Property<"size", ExprRef> {
    let Read = [{ node->getSizeExpr() }];
  }

  def : Creator<[{
    return ctx.getVariableArrayType(elementType, size, sizeModifier,
                                    indexQualifiers.getCVRQualifiers(),
                                    SourceRange(leftBracketLoc,
                                                rightBracketLoc));
  }]>;
}

let Class = DependentSizedArrayType in {
  def : Property<"size", ExprRef> {
    let Read = [{ node->getSizeExpr() }];
  }
  def : Property<"leftBracketLoc", SourceLocation> {
    let Read = [{ node->getLBracketLoc() }];
  }
  def : Property<"rightBracketLoc", SourceLocation> {
    let Read = [{ node->getRBracketLoc() }];
  }

  def : Creator<[{
    return ctx.getDependentSizedArrayType(elementType, size, sizeModifier,
                                          indexQualifiers.getCVRQualifiers(),
                                          SourceRange(leftBracketLoc,
                                                      rightBracketLoc));
  }]>;
}

let Class = VectorType in {
  def : Property<"elementType", QualType> {
    let Read = [{ node->getElementType() }];
  }
  def : Property<"numElements", UInt32> {
    let Read = [{ node->getNumElements() }];
  }
  def : Property<"vectorKind", VectorKind> {
    let Read = [{ node->getVectorKind() }];
  }

  def : Creator<[{
    return ctx.getVectorType(elementType, numElements, vectorKind);
  }]>;
}

let Class = DependentVectorType in {
  def : Property<"elementType", QualType> {
    let Read = [{ node->getElementType() }];
  }
  def : Property<"size", ExprRef> {
    let Read = [{ node->getSizeExpr() }];
  }
  def : Property<"attributeLoc", SourceLocation> {
    let Read = [{ node->getAttributeLoc() }];
  }
  def : Property<"vectorKind", VectorKind> {
    let Read = [{ node->getVectorKind() }];
  }

  def : Creator<[{
    return ctx.getDependentVectorType(elementType, size, attributeLoc,
                                      vectorKind);
  }]>;
}

let Class = ExtVectorType in {
  def : Override {
    let IgnoredProperties = [ "vectorKind" ];
  }

  def : Creator<[{
    return ctx.getExtVectorType(elementType, numElements);
  }]>;
}

let Class = DependentSizedExtVectorType in {
  def : Property<"elementType", QualType> {
    let Read = [{ node->getElementType() }];
  }
  def : Property<"size", ExprRef> {
    let Read = [{ node->getSizeExpr() }];
  }
  def : Property<"attributeLoc", SourceLocation> {
    let Read = [{ node->getAttributeLoc() }];
  }

  def : Creator<[{
    return ctx.getDependentSizedExtVectorType(elementType, size, attributeLoc);
  }]>;
}

let Class = MatrixType in {
  def : Property<"elementType", QualType> {
    let Read = [{ node->getElementType() }];
  }
}

let Class = ConstantMatrixType in {
  def : Property<"numRows", UInt32> {
    let Read = [{ node->getNumRows() }];
  }
  def : Property<"numColumns", UInt32> {
    let Read = [{ node->getNumColumns() }];
  }

  def : Creator<[{
    return ctx.getConstantMatrixType(elementType, numRows, numColumns);
  }]>;
}

let Class = DependentSizedMatrixType in {
  def : Property<"rows", ExprRef> {
    let Read = [{ node->getRowExpr() }];
  }
  def : Property<"columns", ExprRef> {
    let Read = [{ node->getColumnExpr() }];
  }
  def : Property<"attributeLoc", SourceLocation> {
    let Read = [{ node->getAttributeLoc() }];
  }

  def : Creator<[{
    return ctx.getDependentSizedMatrixType(elementType, rows, columns, attributeLoc);
  }]>;
}

let Class = FunctionType in {
  def : Property<"returnType", QualType> {
    let Read = [{ node->getReturnType() }];
  }
  def : Property<"noReturn", Bool> {
    let Read = [{ node->getExtInfo().getNoReturn() }];
  }
  def : Property<"hasRegParm", Bool> {
    let Read = [{ node->getExtInfo().getHasRegParm() }];
  }
  def : Property<"regParm", UInt32> {
    let Read = [{ node->getExtInfo().getRegParm() }];
  }
  def : Property<"callingConvention", CallingConv> {
    let Read = [{ node->getExtInfo().getCC() }];
  }
  def : Property<"producesResult", Bool> {
    let Read = [{ node->getExtInfo().getProducesResult() }];
  }
  def : Property<"noCallerSavedRegs", Bool> {
    let Read = [{ node->getExtInfo().getNoCallerSavedRegs() }];
  }
  def : Property<"noCfCheck", Bool> {
    let Read = [{ node->getExtInfo().getNoCfCheck() }];
  }
  def : Property<"cmseNSCall", Bool> {
    let Read = [{ node->getExtInfo().getCmseNSCall() }];
  }
}

let Class = FunctionNoProtoType in {
  def : Creator<[{
    auto extInfo = FunctionType::ExtInfo(noReturn, hasRegParm, regParm,
                                         callingConvention, producesResult,
                                         noCallerSavedRegs, noCfCheck,
                                         cmseNSCall);
    return ctx.getFunctionNoProtoType(returnType, extInfo);
  }]>;
}

let Class = FunctionProtoType in {
  def : Property<"variadic", Bool> {
    let Read = [{ node->isVariadic() }];
  }
  def : Property<"trailingReturn", Bool> {
    let Read = [{ node->hasTrailingReturn() }];
  }
  def : Property<"methodQualifiers", Qualifiers> {
    let Read = [{ node->getMethodQuals() }];
  }
  def : Property<"refQualifier", RefQualifierKind> {
    let Read = [{ node->getRefQualifier() }];
  }
  def : Property<"exceptionSpecifier", ExceptionSpecInfo> {
    let Read = [{ node->getExceptionSpecInfo() }];
  }
  def : Property<"parameters", Array<QualType>> {
    let Read = [{ node->getParamTypes() }];
  }
  def : Property<"extParameterInfo", Array<ExtParameterInfo>> {
    let Read = [{ node->hasExtParameterInfos()
                    ? node->getExtParameterInfos()
                    : llvm::ArrayRef<FunctionProtoType::ExtParameterInfo>() }];
  }

  def : Creator<[{
    auto extInfo = FunctionType::ExtInfo(noReturn, hasRegParm, regParm,
                                         callingConvention, producesResult,
                                         noCallerSavedRegs, noCfCheck,
                                         cmseNSCall);
    FunctionProtoType::ExtProtoInfo epi;
    epi.ExtInfo = extInfo;
    epi.Variadic = variadic;
    epi.HasTrailingReturn = trailingReturn;
    epi.TypeQuals = methodQualifiers;
    epi.RefQualifier = refQualifier;
    epi.ExceptionSpec = exceptionSpecifier;
    epi.ExtParameterInfos =
      extParameterInfo.empty() ? nullptr : extParameterInfo.data();
    return ctx.getFunctionType(returnType, parameters, epi);
  }]>;
}

let Class = AtomicType in {
  def : Property<"valueType", QualType> {
    let Read = [{ node->getValueType() }];
  }

  def : Creator<[{
    return ctx.getAtomicType(valueType);
  }]>;
}

let Class = UnresolvedUsingType in {
  def : Property<"declaration", DeclRef> {
    let Read = [{ node->getDecl() }];
  }

  def : Creator<[{
    return ctx.getUnresolvedUsingType(cast<UnresolvedUsingTypenameDecl>(declaration));
  }]>;
}

let Class = UsingType in {
  def : Property<"foundDeclaration", UsingShadowDeclRef> {
    let Read = [{ node->getFoundDecl() }];
  }
  def : Property<"underlyingType", QualType> {
    let Read = [{ node->getUnderlyingType() }];
  }

  def : Creator<[{
    return ctx.getUsingType(foundDeclaration, underlyingType);
  }]>;
}

let Class = TypedefType in {
  def : Property<"declaration", DeclRef> {
    let Read = [{ node->getDecl() }];
  }
  def : Property<"underlyingType", QualType> {
    let Read = [{ node->desugar() }];
  }

  def : Creator<[{
    return ctx.getTypedefType(cast<TypedefNameDecl>(declaration), underlyingType);
  }]>;
}

let Class = TypeOfExprType in {
  def : Property<"expression", ExprRef> {
    let Read = [{ node->getUnderlyingExpr() }];
  }

  def : Property<"kind", TypeOfKind> {
    let Read = [{ node->getKind() }];
  }

  def : Creator<[{
    return ctx.getTypeOfExprType(expression, kind);
  }]>;
}

let Class = TypeOfType in {
  def : Property<"unmodifiedType", QualType> {
    let Read = [{ node->getUnmodifiedType() }];
  }

  def : Property<"kind", TypeOfKind> {
    let Read = [{ node->getKind() }];
  }

  def : Creator<[{
    return ctx.getTypeOfType(unmodifiedType, kind);
  }]>;
}

let Class = DecltypeType in {
  def : Property<"underlyingType", QualType> {
    let Read = [{ node->getUnderlyingType() }];
  }
  def : Property<"expression", ExprRef> {
    let Read = [{ node->getUnderlyingExpr() }];
  }

  def : Creator<[{
    return ctx.getDecltypeType(expression, underlyingType);
  }]>;
}

let Class = UnaryTransformType in {
  def : Property<"baseType", QualType> {
    let Read = [{ node->getBaseType() }];
  }
  def : Property<"underlyingType", QualType> {
    let Read = [{ node->getUnderlyingType() }];
  }
  def : Property<"transform", UnaryTypeTransformKind> {
    let Read = [{ node->getUTTKind() }];
  }

  def : Creator<[{
    return ctx.getUnaryTransformType(baseType, underlyingType, transform);
  }]>;
}

let Class = AutoType in {
  def : Property<"deducedType", Optional<QualType>> {
    let Read = [{ makeOptionalFromNullable(node->getDeducedType()) }];
  }
  def : Property<"keyword", AutoTypeKeyword> {
    let Read = [{ node->getKeyword() }];
  }
  def : Property<"typeConstraintConcept", Optional<ConceptDeclRef>> {
    let Read = [{ makeOptionalFromPointer(
        const_cast<const ConceptDecl*>(node->getTypeConstraintConcept())) }];
  }
  def : Property<"typeConstraintArguments", Array<TemplateArgument>> {
    let Read = [{ node->getTypeConstraintArguments() }];
  }
  // FIXME: better enumerated value
  // Only really required when the deduced type is null
  def : Property<"dependence", UInt32> {
    let Read = [{ !node->getDeducedType().isNull() ? 0 :
                  node->containsUnexpandedParameterPack() ? 2 :
                  node->isDependentType() ? 1 : 0 }];
  }

  def : Creator<[{
    return ctx.getAutoType(makeNullableFromOptional(deducedType), keyword,
                           /*isDependentWithoutDeducedType*/ dependence > 0,
                           /*isPackWithoutDeducedType*/ dependence > 1,
                           makePointerFromOptional(typeConstraintConcept),
                           typeConstraintArguments);
  }]>;
}

let Class = DeducedTemplateSpecializationType in {
  def : Property<"templateName", Optional<TemplateName>> {
    let Read = [{ makeOptionalFromNullable(node->getTemplateName()) }];
  }
  def : Property<"deducedType", QualType> {
    let Read = [{ node->getDeducedType() }];
  }
  // Only really required when the deduced type is null
  def : Property<"dependent", Bool> {
    let Read = [{ !node->getDeducedType().isNull()
                    ? false : node->isDependentType() }];
  }

  def : Creator<[{
    return ctx.getDeducedTemplateSpecializationType(
                                     makeNullableFromOptional(templateName),
                                     deducedType, dependent);
  }]>;
}

let Class = TagType in {
  def : Property<"dependent", Bool> {
    let Read = [{ node->isDependentType() }];
  }
  def : Property<"declaration", DeclRef> {
    // We don't know which declaration was originally referenced here, and we
    // cannot reference a declaration that follows the use (because that can
    // introduce deserialization cycles), so conservatively generate a
    // reference to the first declaration.
    // FIXME: If this is a reference to a class template specialization, that
    // can still introduce a deserialization cycle.
    let Read = [{ node->getDecl()->getCanonicalDecl() }];
  }
}

let Class = EnumType in {
  def : Creator<[{
    QualType result = ctx.getEnumType(cast<EnumDecl>(declaration));
    if (dependent)
      const_cast<Type *>(result.getTypePtr())
          ->addDependence(TypeDependence::DependentInstantiation);
    return result;
  }]>;
}

let Class = RecordType in {
  def : Creator<[{
    auto record = cast<RecordDecl>(declaration);
    QualType result = ctx.getRecordType(record);
    if (dependent)
      const_cast<Type *>(result.getTypePtr())
          ->addDependence(TypeDependence::DependentInstantiation);
    return result;
  }]>;
}

let Class = ElaboratedType in {
  def : Property<"keyword", ElaboratedTypeKeyword> {
    let Read = [{ node->getKeyword() }];
  }
  def : Property<"qualifier", NestedNameSpecifier> {
    let Read = [{ node->getQualifier() }];
  }
  def : Property<"namedType", QualType> {
    let Read = [{ node->getNamedType() }];
  }
  def : Property<"ownedTag", Optional<TagDeclRef>> {
    let Read = [{ makeOptionalFromPointer(
                    const_cast<const TagDecl *>(node->getOwnedTagDecl())) }];
  }

  def : Creator<[{
    return ctx.getElaboratedType(keyword, qualifier, namedType,
                                 makePointerFromOptional(ownedTag));
  }]>;
}

let Class = InjectedClassNameType in {
  def : Property<"declaration", DeclRef> {
    // FIXME: drilling down to the canonical declaration is what the
    // existing serialization code was doing, but it's not clear why.
    let Read = [{ node->getDecl()->getCanonicalDecl() }];
  }
  def : Property<"injectedSpecializationType", QualType> {
    let Read = [{ node->getInjectedSpecializationType() }];
  }

  def : Creator<[{
    // FIXME: ASTContext::getInjectedClassNameType is not currently suitable
    // for AST reading, too much interdependencies.
    const Type *T = nullptr;
    auto typeDecl = cast<CXXRecordDecl>(declaration);
    for (auto *DI = typeDecl; DI; DI = DI->getPreviousDecl()) {
      if (const Type *existing = DI->getTypeForDecl()) {
        T = existing;
        break;
      }
    }
    if (!T) {
      T = new (ctx, TypeAlignment)
            InjectedClassNameType(typeDecl, injectedSpecializationType);
      for (auto *DI = typeDecl; DI; DI = DI->getPreviousDecl())
        DI->setTypeForDecl(T);
    }
    return QualType(T, 0);
  }]>;
}

let Class = ParenType in {
  def : Property<"innerType", QualType> {
    let Read = [{ node->getInnerType() }];
  }

  def : Creator<[{
    return ctx.getParenType(innerType);
  }]>;  
}

let Class = MacroQualifiedType in {
  def : Property<"underlyingType", QualType> {
    let Read = [{ node->getUnderlyingType() }];
  }
  def : Property<"macroIdentifier", Identifier> {
    let Read = [{ node->getMacroIdentifier() }];
  }

  def : Creator<[{
    return ctx.getMacroQualifiedType(underlyingType, macroIdentifier);
  }]>;
}

let Class = AttributedType in {
  def : Property<"modifiedType", QualType> {
    let Read = [{ node->getModifiedType() }];
  }
  def : Property<"equivalentType", QualType> {
    let Read = [{ node->getEquivalentType() }];
  }
  def : Property<"attribute", AttrKind> {
    let Read = [{ node->getAttrKind() }];
  }

  def : Creator<[{
    return ctx.getAttributedType(attribute, modifiedType, equivalentType);
  }]>;
}

let Class = BTFTagAttributedType in {
  def : Property<"attr", BTFTypeTagAttr> {
    let Read = [{ node->getAttr() }];
  }
  def : Property<"wrappedType", QualType> {
    let Read = [{ node->getWrappedType() }];
  }

  def : Creator<[{
    return ctx.getBTFTagAttributedType(attr, wrappedType);
  }]>;
}

let Class = DependentAddressSpaceType in {
  def : Property<"pointeeType", QualType> {
    let Read = [{ node->getPointeeType() }];
  }
  def : Property<"addressSpace", ExprRef> {
    let Read = [{ node->getAddrSpaceExpr() }];
  }
  def : Property<"attributeLoc", SourceLocation> {
    let Read = [{ node->getAttributeLoc() }];
  }

  def : Creator<[{
    return ctx.getDependentAddressSpaceType(pointeeType, addressSpace,
                                            attributeLoc);
  }]>;
}

let Class = TemplateSpecializationType in {
  def : Property<"dependent", Bool> {
    let Read = [{ node->isDependentType() }];
  }
  def : Property<"templateName", TemplateName> {
    let Read = [{ node->getTemplateName() }];
  }
  def : Property<"templateArguments", Array<TemplateArgument>> {
    let Read = [{ node->template_arguments() }];
  }
  def : Property<"underlyingType", Optional<QualType>> {
    let Read = [{
      node->isTypeAlias()
        ? std::optional<QualType>(node->getAliasedType())
        : node->isCanonicalUnqualified()
            ? std::nullopt
            : std::optional<QualType>(node->getCanonicalTypeInternal())
    }];
  }

  def : Creator<[{
    QualType result;
    if (!underlyingType) {
      result = ctx.getCanonicalTemplateSpecializationType(templateName,
                                                          templateArguments);
    } else {
      result = ctx.getTemplateSpecializationType(templateName,
                                                 templateArguments,
                                                 *underlyingType);
    }
    if (dependent)
      const_cast<Type *>(result.getTypePtr())
          ->addDependence(TypeDependence::DependentInstantiation);
    return result;
  }]>;
}

let Class = DependentTemplateSpecializationType in {
  def : Property<"keyword", ElaboratedTypeKeyword> {
    let Read = [{ node->getKeyword() }];
  }
  def : Property<"qualifier", NestedNameSpecifier> {
    let Read = [{ node->getQualifier() }];
  }
  def : Property<"name", Identifier> {
    let Read = [{ node->getIdentifier() }];
  }
  def : Property<"templateArguments", Array<TemplateArgument>> {
    let Read = [{ node->template_arguments() }];
  }

  def : Creator<[{
    return ctx.getDependentTemplateSpecializationType(keyword, qualifier,
                                                      name, templateArguments);
  }]>;
}

let Class = TemplateTypeParmType in {
  def : Property<"depth", UInt32> {
    let Read = [{ node->getDepth() }];
  }
  def : Property<"index", UInt32> {
    let Read = [{ node->getIndex() }];
  }
  def : Property<"isParameterPack", Bool> {
    let Read = [{ node->isParameterPack() }];
  }
  def : Property<"declaration", Optional<TemplateTypeParmDeclRef>> {
    let Read = [{ makeOptionalFromPointer(
                    const_cast<const TemplateTypeParmDecl*>(node->getDecl())) }];
  }

  def : Creator<[{
    return ctx.getTemplateTypeParmType(depth, index, isParameterPack,
                                       makePointerFromOptional(declaration));
  }]>;
}

let Class = SubstTemplateTypeParmType in {
  def : Property<"replacementType", QualType> {
    let Read = [{ node->getReplacementType() }];
  }
  def : Property<"associatedDecl", DeclRef> {
    let Read = [{ node->getAssociatedDecl() }];
  }
  def : Property<"Index", UInt32> {
    let Read = [{ node->getIndex() }];
  }
  def : Property<"PackIndex", Optional<UInt32>> {
    let Read = [{ node->getPackIndex() }];
  }

  // The call to getCanonicalType here existed in ASTReader.cpp, too.
  def : Creator<[{
    return ctx.getSubstTemplateTypeParmType(
        replacementType, associatedDecl, Index, PackIndex);
  }]>;
}

let Class = PackExpansionType in {
  def : Property<"pattern", QualType> {
    let Read = [{ node->getPattern() }];
  }
  def : Property<"numExpansions", Optional<UInt32>> {
    let Read = [{ node->getNumExpansions() }];
  }

  def : Creator<[{
    return ctx.getPackExpansionType(pattern, numExpansions,
                                    /*ExpectPackInType*/false);
  }]>;
}

let Class = SubstTemplateTypeParmPackType in {
  def : Property<"associatedDecl", DeclRef> {
    let Read = [{ node->getAssociatedDecl() }];
  }
  def : Property<"Index", UInt32> {
    let Read = [{ node->getIndex() }];
  }
  def : Property<"Final", Bool> {
    let Read = [{ node->getFinal() }];
  }
  def : Property<"replacementPack", TemplateArgument> {
    let Read = [{ node->getArgumentPack() }];
  }

  def : Creator<[{
    return ctx.getSubstTemplateTypeParmPackType(
                        associatedDecl, Index, Final, replacementPack);
  }]>;
}

let Class = BuiltinType in {
  def : Property<"kind", BuiltinTypeKind> {
    let Read = [{ node->getKind() }];
  }

  def : Creator<[{
      switch (kind) {
#define IMAGE_TYPE(IMGTYPE, ID, SINGLETON_ID, ACCESS, SUFFIX) \
      case BuiltinType::ID: return ctx.SINGLETON_ID;
#include "clang/Basic/OpenCLImageTypes.def"

#define EXT_OPAQUE_TYPE(EXTTYPE, ID, EXT) \
      case BuiltinType::ID: return ctx.ID##Ty;
#include "clang/Basic/OpenCLExtensionTypes.def"

#define SVE_TYPE(NAME, ID, SINGLETON_ID) \
      case BuiltinType::ID: return ctx.SINGLETON_ID;
#include "clang/Basic/AArch64SVEACLETypes.def"

#define PPC_VECTOR_TYPE(NAME, ID, SIZE) \
      case BuiltinType::ID: return ctx.ID##Ty;
#include "clang/Basic/PPCTypes.def"

#define RVV_TYPE(NAME, ID, SINGLETON_ID) \
      case BuiltinType::ID: return ctx.SINGLETON_ID;
#include "clang/Basic/RISCVVTypes.def"

#define WASM_TYPE(NAME, ID, SINGLETON_ID) \
      case BuiltinType::ID: return ctx.SINGLETON_ID;
#include "clang/Basic/WebAssemblyReferenceTypes.def"

#define BUILTIN_TYPE(ID, SINGLETON_ID) \
      case BuiltinType::ID: return ctx.SINGLETON_ID;
#include "clang/AST/BuiltinTypes.def"
      }
      llvm_unreachable("unreachable builtin case");
  }]>;
}

let Class = DependentNameType in {
  def : Property<"keyword", ElaboratedTypeKeyword> {
    let Read = [{ node->getKeyword() }];
  }
  def : Property<"qualifier", NestedNameSpecifier> {
    let Read = [{ node->getQualifier() }];
  }
  def : Property<"name", Identifier> {
    let Read = [{ node->getIdentifier() }];
  }
  def : Property<"underlyingType", Optional<QualType>> {
    let Read = [{
      node->isCanonicalUnqualified()
        ? std::nullopt
        : std::optional<QualType>(node->getCanonicalTypeInternal())
    }];
  }

  def : Creator<[{
    QualType canon = (underlyingType
                        ? ctx.getCanonicalType(*underlyingType)
                        : QualType());
    return ctx.getDependentNameType(keyword, qualifier, name, canon);
  }]>;
}

let Class = ObjCObjectType in {
  def : Property<"baseType", QualType> {
    let Read = [{ node->getBaseType() }];
  }
  def : Property<"typeArgsAsWritten", Array<QualType>> {
    let Read = [{ node->getTypeArgsAsWritten() }];
  }
  def : Property<"qualifiers", Array<ObjCProtocolDeclRef>> {
    let Read = [{ node->getProtocols() }];
  }
  def : Property<"isKindOfTypeAsWritten", Bool> {
    let Read = [{ node->isKindOfTypeAsWritten() }];
  }

  def : Creator<[{
    return ctx.getObjCObjectType(baseType, typeArgsAsWritten, qualifiers,
                                 isKindOfTypeAsWritten);
  }]>;
}

let Class = ObjCInterfaceType in {
  // We don't actually want any of the properties of the superclass.
  def : Override {
    let IgnoredProperties = [ "baseType", "typeArgsAsWritten",
                              "qualifiers", "isKindOfTypeAsWritten" ];
  }

  def : Property<"declaration", DeclRef> {
    // FIXME: drilling down to the canonical declaration is what the
    // existing serialization code was doing, but it's not clear why.
    let Read = [{ node->getDecl()->getCanonicalDecl() }];
  }

  def : Creator<[{
    return ctx.getObjCInterfaceType(
             cast<ObjCInterfaceDecl>(declaration->getCanonicalDecl()));
  }]>;
}

let Class = ObjCTypeParamType in {
  def : Property<"declaration", ObjCTypeParamDeclRef> {
    let Read = [{ node->getDecl() }];
  }  
  def : Property<"qualifiers", Array<ObjCProtocolDeclRef>> {
    let Read = [{ node->getProtocols() }];
  }

  def : Creator<[{
    return ctx.getObjCTypeParamType(declaration, qualifiers);
  }]>;
}

let Class = ObjCObjectPointerType in {
  def : Property<"pointeeType", QualType> {
    let Read = [{ node->getPointeeType() }];
  }

  def : Creator<[{
    return ctx.getObjCObjectPointerType(pointeeType);
  }]>;
}

let Class = PipeType in {
  def : Property<"elementType", QualType> {
    let Read = [{ node->getElementType() }];
  }
  def : Property<"isReadOnly", Bool> {
    let Read = [{ node->isReadOnly() }];
  }

  def : Creator<[{
    return ctx.getPipeType(elementType, isReadOnly);
  }]>;
}

let Class = BitIntType in {
  def : Property<"isUnsigned", Bool> {
    let Read = [{ node->isUnsigned() }];
  }
  def : Property <"numBits", UInt32> {
    let Read = [{ node->getNumBits() }];
  }

  def : Creator<[{
    return ctx.getBitIntType(isUnsigned, numBits);
  }]>;
}

let Class = DependentBitIntType in {
  def : Property<"isUnsigned", Bool> {
    let Read = [{ node->isUnsigned() }];
  }
  def : Property <"numBitsExpr", ExprRef> {
    let Read = [{ node->getNumBitsExpr() }];
  }
  def : Creator<[{
    return ctx.getDependentBitIntType(isUnsigned, numBitsExpr);
  }]>;
}
